{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# list 与 tuple\n",
    "\n",
    "## list\n",
    "\n",
    "内置数据类型：列表\n",
    "\n",
    "`list`是一种有序集合，可以随时添加或删除其中的元素\n",
    "\n",
    "`len`：获取`list`元素的个数\n",
    "\n",
    "使用索引号访问列表元素，索引号从`0`开始\n",
    "\n",
    "用`-1`做索引表示最后一个元素。以此类推，`-2`，`-3`，`4`分别表示倒数第二，倒数第三，倒数第四个元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['张三', '李四', '王五']\n",
      "3\n",
      "张三\n",
      "李四\n",
      "王五\n"
     ]
    },
    {
     "ename": "IndexError",
     "evalue": "list index out of range",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mIndexError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-3-f59ab459aa27>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mclassmate\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mclassmate\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mclassmate\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m    \u001b[0;31m#下标越界\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mIndexError\u001b[0m: list index out of range"
     ]
    }
   ],
   "source": [
    "classmate = ['张三', '李四', '王五']\n",
    "print(classmate)\n",
    "print(len(classmate))    #获取list元素个数\n",
    "print(classmate[0])    #索引号从0开始\n",
    "print(classmate[1])\n",
    "print(classmate[2])\n",
    "print(classmate[3])    #下标越界\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(classmate[-1])    #-1直接获取最后的元素\n",
    "print(classmate[-2])    #倒数第二个元素\n",
    "print(classmate[-3])\n",
    "print(classmate[-4])    #下标越界"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`append()`：追加元素到`list`末尾\n",
    "\n",
    "`insert()`：把元素插入到指定位置\n",
    "\n",
    "`pop()`：删除末尾元素\n",
    "\n",
    "`pop(i)`：删除指定元素，`i`为索引号\n",
    "\n",
    "替换某元素：直接对该元素赋值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['张三', '李四', '王五', '马六']\n",
      "['张三', '陈二', '李四', '王五', '马六']\n",
      "['张三', '陈二', '李四', '王五']\n",
      "['张三', '陈二', '王五']\n",
      "['张三', 'chener', '王五']\n"
     ]
    }
   ],
   "source": [
    "classmate.append('马六')\n",
    "print(classmate)\n",
    "classmate.insert(1, '陈二')\n",
    "print(classmate)\n",
    "classmate.pop()\n",
    "print(classmate)\n",
    "classmate.pop(2)\n",
    "print(classmate)\n",
    "classmate[1] = 'chener'\n",
    "print(classmate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`list`里各元素数据类型可以不同\n",
    "\n",
    "`list`的元素也可以是另一个`list`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['java', 'c++', ['asp', 'php'], 'vb']的长度是：4\n",
      "['java', 'c++', ['asp', 'php'], 'vb']\n"
     ]
    }
   ],
   "source": [
    "L = ['apple', 123, True]\n",
    "s = ['java', 'c++', ['asp', 'php'], 'vb']\n",
    "print('%s的长度是：%d' %(s, len(s)))\n",
    "p = ['asp', 'php']\n",
    "s = ['java', 'c++', p, 'vb']\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "要访问'php'，可使用`p[1]`或`s[2][1]`\n",
    "\n",
    "s可看作二维数组，类似的还有三维、四维数组...\n",
    "\n",
    "空list：一个元素都没有，长度为0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n"
     ]
    }
   ],
   "source": [
    "L = []\n",
    "print(len(L))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## tuple\n",
    "\n",
    "元组：有序列表，一旦初始化就不能修改\n",
    "\n",
    "没有`append()`、`insert()`这些方法，其它获取元素的方法跟`list`一样，但不能赋值。\n",
    "\n",
    "不可变的`tuple`有什么意义？因为`tuple`不可变，所以代码更安全。如果可能，能用`tuple`代替`list`就尽量用`tuple`。\n",
    "\n",
    "`tuple`的陷阱：当你定义一个`tuple`时，在定义的时候，`tuple`的元素就必须被确定下来"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('张三', '李四', '王五')\n"
     ]
    }
   ],
   "source": [
    "classmate = ('张三', '李四', '王五')\n",
    "print(classmate)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "定义空的`tuple`，可写成`()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "()\n"
     ]
    }
   ],
   "source": [
    "t = ()\n",
    "print(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但定义只有一个元素的`tuple`，如果这样定义："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "t = (1)\n",
    "print(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "定义的不是`tuple`，是`1`这个数。这是因为括号`()`既可以表示`tuple`，又可以表示数学公式中的小括号，这就产生了歧义，因此，Python规定，这种情况下，按小括号进行计算，计算结果自然是`1`。\n",
    "\n",
    "所以，只有1个元素的`tuple`定义时必须加一个逗号`,`，来消除歧义.\n",
    "\n",
    "Python在显示只有1个元素的`tuple`时，也会加一个逗号`,`，以免你误解成数学计算意义上的括号。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1,)\n"
     ]
    }
   ],
   "source": [
    "t = (1,)\n",
    "print(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "“可变”的`tuple`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('a', 'b', ['X', 'Y'])\n"
     ]
    }
   ],
   "source": [
    "t = ('a', 'b', ['A', 'B'])\n",
    "t[2][0] = 'X'\n",
    "t[2][1] = 'Y'\n",
    "print(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个`tuple`定义的时候有3个元素，分别是`'a'`，`'b'`和一个`list`。不是说`tuple`一旦定义后就不可变了吗？怎么后来又变了？\n",
    "\n",
    "别急，我们先看看定义的时候`tuple`包含的3个元素：\n",
    "\n",
    "![tuple1](../pics/tuple1.png)\n",
    "\n",
    "当我们把list的元素'A'和'B'修改为'X'和'Y'后，tuple变为：\n",
    "\n",
    "![tuple1](../pics/tuple2.png)\n",
    "\n",
    "表面上看，tuple的元素确实变了，但其实变的不是tuple的元素，而是list的元素。tuple一开始指向的list并没有改成别的list，所以，tuple所谓的“不变”是说，tuple的每个元素，指向永远不变。即指向'a'，就不能改成指向'b'，指向一个list，就不能改成指向其他对象，但指向的这个list本身是可变的！\n",
    "\n",
    "理解了“指向不变”后，要创建一个内容也不变的tuple怎么做？那就必须保证tuple的每一个元素本身也不能变。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 小结\n",
    "\n",
    "list和tuple是Python内置的有序集合，一个可变，一个不可变。根据需要来选择使用它们。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
